import { BUNDLE_TYPE_ENUM } from "../base/EnumIndex";
import { ResManager } from "../manager/ResManager";

const env = window["wx"] || window["tt"] || window["ks"] || window["qq"];
/** 游戏常用工具类 */
export class Tools {
    public static storageKey: string = "_v1.0.0";
    /**
        * 存储本地数据
        * @param {*} isObject 是否是一个对象或者数组
        */
    public static setStorage(key: string, value: any, isObject = false) {
        key = this.storageKey + key;
        if (env) {
            return env.setStorageSync(key, value);
        }
        if (isObject) {
            value = JSON.stringify(value);
        }
        /** 默认cocos 存储数据方法 */
        cc.sys.localStorage.setItem(key, value);
    };

    /**
    * 获取存储数据
    * @param {*} isObject 是否是一个对象或者数组
    */
    public static getStorage(key: string, isObject = false) {
        key = this.storageKey + key;
        let temp = null;

        if (env) {
            temp = <any>env.getStorageSync(key);
            if (temp == "") {
                temp = null;
            }
        } else {
            temp = <any>cc.sys.localStorage.getItem(key);
            if (!temp || temp.toString() == "NaN" || temp.toString() == "null") {
                temp = null;
            } else if (isObject) {
                temp = JSON.parse(temp);
            } else if (typeof temp === "boolean") {

            } else if (!isNaN(temp)) {
                temp = parseInt(temp);
            }
        }
        return temp;
    };
    /** 适配 */
    public static updateResolution() {
        let canvas = cc.find('Canvas').getComponent(cc.Canvas);
        let a = canvas.designResolution.width / canvas.designResolution.height;
        let b = cc.winSize.width / cc.winSize.height;
        canvas.fitHeight = a < b;
        canvas.fitWidth = a >= b;
        // cc.log(a < b, a >= b)
        cc.view.setResizeCallback(() => {
            // cc.log(canvas.designResolution, cc.winSize, canvas)
            // cc.log(cc.view.getDesignResolutionSize(), cc.view.getVisibleSize())
        });
    }
    /** pop界面动画 */
    public static popShowAnim(node: cc.Node, callback?: Function, ...args: unknown[]) {
        // node.runAction(cc.fadeTo(0.3, 180));
        node.y += 1000;
        node.runAction(cc.sequence(
            cc.moveBy(0.3, cc.v2(0, -1000)).easing(cc.easeBackOut()),
            cc.callFunc(() => {
                callback && callback(args);
            })
        ));

        // node.setScale(0);
        // cc.tween(node).to(0.2, { scale: 1 }, { easing: cc.easing.backOut }).call(() => {
        //     callback && callback(args);
        // }).start();
    }
    /** pop界面动画 */
    public static popCloseAnim(node: cc.Node, callback?: Function, ...args: unknown[]) {
        let animTime = 0.2;
        // cc.tween(node).to(0.2, { scale: 0 }, { easing: cc.easing.backIn }).call(() => {
        //     callback && callback(args);
        // }).start();
        cc.tween(node).to(animTime, { opacity: 0 }).call(() => {
            callback && callback(args);
        }).start();

        return animTime;
    }
    //-----------------------------节点预制体相关-------------------------------
    /**
     * 新建一个预制体在场景里
     * @param prefab 预制体
     * @param callFunc 加载预制体 完成后回调
     * @param parent 存放预制体的父节点
     * @param Pos 预制体的坐标
     * @param zindex 预制体的层级
     */
    public static newPrefab(prefab: cc.Prefab, parent?: cc.Node, Pos?: cc.Vec2, zindex = 0, callFunc?: (age?: cc.Node) => void): cc.Node {
        return NodeTools._ins.newPrefab(prefab, callFunc, parent, this.getV3ForV2(Pos), zindex);
    }
    /**
     * 新建一个图片在场景里
     * @param sprName 图片名字或url
     * @param callFunc 加载预制体 完成后回调
     * @param parent 存放预制体的父节点
     * @param Pos 预制体的坐标
     * @param zindex 预制体的层级
     */
    public static newSprite(spf: cc.SpriteFrame, parent?: cc.Node): cc.Node {
        return NodeTools._ins.newSprite(spf, parent);
    } spf
    /**
     * 设置一个节点的SpriteFrame
     * @param nodeT 节点的Node
     * @param spf 图片
     */
    public static setSpriteFrame(nodeT: cc.Node, spf: cc.SpriteFrame) {
        NodeTools._ins.setSpriteFrame(nodeT, spf);
    }
    /** 设置一个节点的 groupIndex 包含子物体 */
    public static setNodeGroupIndex(nodeT: cc.Node, groupIndex: number) {
        NodeTools._ins.setNodeGroupIndex(nodeT, groupIndex);
    }

    /**
     * 节点的图片置灰色或者默认
     * @param state 0 默认  1 灰色 
     */
    public static setSpriteState(nodeT: cc.Node, state: number, isAllChild: boolean = false) {
        NodeTools._ins.setSpriteState(nodeT, state, isAllChild);
    };
    /** 切换父物体 不改变显示位置*/
    public static setNodeParent(node: cc.Node, parent: cc.Node) {
        NodeTools._ins.setNodeParent(node, parent);
    };
    /** 判断两个节点是否相交 */
    public static isNodeInterNode(node1: cc.Node, node2: cc.Node) {
        return node1.getBoundingBoxToWorld().intersects(node2.getBoundingBoxToWorld());
    };
    /** 通过名字获取节点 */
    public static getChildForName(name: string, parentNode?: cc.Node) {
        if (!name) { return null; }
        parentNode = parentNode || cc.director.getScene().getChildByName("Canvas");
        for (let i = 0; i < parentNode.children.length; i++) {
            const node = parentNode.children[i];
            if (node.name == name) {
                return node;
            }
            if (node.children.length > 0) {
                let temp = this.getChildForName(name, node);
                if (temp) {
                    return temp;
                }
            }
        }
        return null;
    };
    //----------------------------------数学数组相关----------------------------------
    /**
     * 获取随机数
     * @param isInteger 是否随机整数  默认整数
     */
    public static random(x1: number, x2: number, isInteger = true): number {
        return MathTools._ins.random(x1, x2, isInteger);
    }
    /**
     * 根据概率数组 随机概率 返回数组的index
     * @param chooseArr 需要随机概率的数组 例如[0.05,0.1,0.2,0.3]
     */
    public static chooseRandom(chooseArr: Array<number>) {
        return MathTools._ins.chooseRandom(chooseArr);
    }
    /** 传入一个弧度 返回一个Y轴折射后的弧度 */
    public static refractionY(rad: number) {
        return MathTools._ins.refractionY(rad);
    };
    /** 传入一个弧度 返回一个X轴折射后的弧度 */
    public static refractionX(rad: number) {
        return MathTools._ins.refractionX(rad);
    };
    /** 重新打乱一个数组的顺序  洗牌 */
    public static aginSortArr(Arr: Array<any>) {
        MathTools._ins.aginSortArr(Arr);
    };
    /**
     * 将一个数组 按照里面的对象排序 
     * @param tempArr 传入的数组
     * @param sortName 对象属性名字
     * @param isReverse 是否倒序
     */
    public static sortArrForObject(tempArr: Array<any>, sortName: string, isReverse = false) {
        MathTools._ins.sortArrForObject(tempArr, sortName, isReverse);
    };
    /**
     * 取一定范围内不重复的数字
     * @param minNum 最小取值范围
     * @param maxNum 最大取值范围
     * @param getNum 取几个数字
     */
    public static getDiffNumRandom(minNum: number, maxNum: number, getNum: number) {
        return MathTools._ins.getDiffNumRandom(minNum, maxNum, getNum);
    };
    /** 通过number 获取中文数字 15  十五 */
    public static getChineseForNum(num: number) {
        return MathTools._ins.DigitToChinese(num);
    };
    //--------------------------------向量坐标计算相关------------------------------------
    /**
     * 根据两个点  求角度
     * @param pos1 起始点坐标
     * @param pos2 结束点坐标
     * @param isVertical 是否以竖直方向为0度开始
     */
    public static getAngleForPos(pos1: cc.Vec2 | cc.Vec3, pos2: cc.Vec2 | cc.Vec3, isVertical = false): number {
        return VectTools._ins.getAngleForPos(this.getV2ForV3(pos1), this.getV2ForV3(pos2), isVertical);
    };
    /** 获取两个坐标之间的距离 */
    public static getDistance(pos1: cc.Vec2 | cc.Vec3, pos2: cc.Vec2 | cc.Vec3): number {
        return VectTools._ins.getDistance(this.getV2ForV3(pos1), this.getV2ForV3(pos2));
    };
    /** 通过V3 获取V2 */
    public static getV2ForV3(pos?: cc.Vec2 | cc.Vec3): cc.Vec2 {
        if (!pos) { return null; }
        return cc.v2(pos.x, pos.y);
    };
    /** 通过V3 获取V2 */
    public static getV3ForV2(pos?: cc.Vec2 | cc.Vec3): cc.Vec3 {
        if (!pos) { return null; }
        return cc.v3(pos.x, pos.y, 0);
    };
    /**
     * 根据一个角度和长度 计算相对应的坐标
     * @param angle 角度
     * @param len 该角度上的长度
     * @param startPos 初始的坐标
     */
    public static getPosForAngleLen(angle: number, len: number, startPos: cc.Vec2 = cc.v2(0, 0)) {
        return VectTools._ins.getPosForAngleLen(angle, len, startPos);
    }
    /**
     * 获取节点在另一个节点下的坐标
     * @param obj 节点
     * @param mainObj 相对于的另一个节点
     */
    public static getToNodePosForNode(obj: cc.Node, mainObj: cc.Node): cc.Vec2 {
        return VectTools._ins.getToNodePosForNode(obj, mainObj);
    };
    /** 获取节点的世界坐标 */
    public static getToWorldPosAR(obj: cc.Node) {
        return VectTools._ins.getToWorldPosAR(obj);
    }
    /**
     * 通过世界坐标 获取相对节点的坐标
     * @param worldPos 世界坐标
     * @param obj 相对节点下的
     */
    public static getToNodePosForWorld(worldPos: cc.Vec2, obj: cc.Node) {
        return VectTools._ins.getToNodePosForWorld(worldPos, obj);
    }
    //--------------------------------数组操作相关------------------------------------
    /** 根据value值 从数组里面移除 */
    public static removeArrForValue(tempArr: Array<any>, value: any) {
        return tempArr.splice(tempArr.indexOf(value), 1);
    }
    /** 从数组里面添加一个该数组里没有的元素 */
    public static addArrNoValue(tempArr: Array<any>, value: any) {
        if (tempArr.indexOf(value) < 0) {
            tempArr.push(value);
            return true;
        }
        return false;
    }
    /** 从数组指定位置 插入某个元素 */
    public static addArrIndex(tempArr: Array<any>, index: number, value: any) {
        return tempArr.splice(index, 0, value);
    }
    //--------------------------------其他------------------------------------
    /**
     *  字符串指定位置插入新字符 
     * @param soure 需要操作的字符串
     * @param start 从那个位置开始插入
     * @param newStr 插入的新的字符
     */
    public static insertStrForIndex(soure: string, start: number, newStr: string): string {
        return soure.slice(0, start) + newStr + soure.slice(start);
    };
    /**
     * 数字整数前边补零 并返回字符串
     * @param num 传入的数字
     * @param length 前边补几个零
     */
    public static prefixInteger(num: number, length = 2): string {
        return (Array(length).join('0') + num).slice(-length);
    };
    /** 获取系统语言 */
    public static getLanguageType(): string {
        var langNumType = "EN";   //默认英语
        if (cc.sys.language == cc.sys.LANGUAGE_CHINESE) {
            if (cc.sys.languageCode.toLowerCase().indexOf("zh-cn") != -1 ||
                cc.sys.languageCode.toLowerCase().indexOf("zh_cn") != -1) {
                langNumType = "CN";  //简体
            } else {
                langNumType = "CHT";  //繁体
            }
        } else if (cc.sys.language == cc.sys.LANGUAGE_KOREAN) {
            langNumType = "KOR"; //韩语
        }
        else if (cc.sys.language == cc.sys.LANGUAGE_JAPANESE) {
            langNumType = "JP"; //日语
        }
        else if (window.navigator.language == "th-TH") {
            langNumType = "TH"; //泰语
        }
        return langNumType;
    }
}


/** 节点相关 工具类 */
class NodeTools {
    /** 单例模式 */
    private static _instance: NodeTools = new NodeTools();
    private constructor() { }
    public static get _ins() {
        return this._instance;
    }

    /** 新建一个预制体在场景里 */
    public newPrefab(prefab: cc.Prefab, callFunc?: (age?: cc.Node) => void, parent?: cc.Node, Pos?: cc.Vec3, zindex = 0): cc.Node {
        let clone = cc.instantiate(prefab);
        if (parent) { parent.addChild(clone, zindex) };
        if (Pos) { clone.position = cc.v3(Pos.x, Pos.y, 0) };
        if (callFunc != null) {
            callFunc(clone);
        }

        return clone;
    }
    /** 新建一个图片在场景里 */
    public newSprite(spf: cc.SpriteFrame, parent?: cc.Node) {
        let sprite = new cc.Node();
        sprite.name = spf.name;
        sprite.addComponent(cc.Sprite).spriteFrame = spf;
        if (parent) { parent.addChild(sprite) };

        return sprite;
    }
    /** 设置一个节点的SpriteFrame */
    public setSpriteFrame(nodeT: cc.Node, spf: cc.SpriteFrame) {
        nodeT.getComponent(cc.Sprite).spriteFrame = spf
    }
    /** 设置一个节点的 groupIndex 包含子物体 */
    public setNodeGroupIndex(nodeT: cc.Node, groupIndex: number) {
        nodeT.groupIndex = groupIndex;
        for (let i = 0; i < nodeT.children.length; i++) {
            this.setNodeGroupIndex(nodeT.children[i], groupIndex);
        }
    }

    /** 图片置灰 或者  恢复 */
    public setSpriteState(nodeT: cc.Node, state: number, isAllChild: boolean) {
        let matUrl = state == 0 ? "builtin-2d-sprite" : "builtin-2d-gray-sprite";
        ResManager.ins.loadRes("materials/" + matUrl, cc.Material, BUNDLE_TYPE_ENUM.MAIN).then((Material: cc.Material) => {
            if (!nodeT["_components"]) {
                return;
            }
            if (isAllChild) {
                let coms = nodeT.getComponentsInChildren(cc.Sprite);
                for (let i = 0; i < coms.length; i++) {
                    coms[i].setMaterial(0, Material);
                }
                return;
            }
            nodeT.getComponent(cc.Sprite).setMaterial(0, Material);
        });
    };
    /** 切换父物体 不改变坐标 */
    public setNodeParent(node: cc.Node, parent: cc.Node) {
        let Pos = VectTools._ins.getToNodePosForNode(node, parent);
        node.parent = parent;
        node.position = cc.v3(Pos.x, Pos.y);
    };
}
/** 数学数组计算相关 工具类 */
class MathTools {
    /** 单例模式 */
    private static _instance: MathTools = new MathTools();
    private constructor() { }
    public static get _ins() {
        return this._instance;
    }

    /** 获取随机数 */
    public random(x1: number, x2: number, isInteger = true): number {
        if (isInteger) {
            return x1 + Math.floor(Math.random() * (x2 - x1 + 1));
        }
        return Math.random() * (x2 - x1) + x1;
    }
    /**  根据概率数组 随机概率 返回数组的index */
    public chooseRandom(chooseArr: Array<number>) {
        let total = 0;  //概率总值
        //首先计算出概率的总值，用来计算随机范围
        for (let i = 0; i < chooseArr.length; i++) {
            total += chooseArr[i];
        }
        let randNum = this.random(0, total, false)
        for (let i = 0; i < chooseArr.length; i++) {
            if (randNum < chooseArr[i] && chooseArr[i] > 0) {
                return i;
            } else {
                randNum -= chooseArr[i];
            }
        }
        return chooseArr.length - 1;
    }
    /** 弧度折射Y轴 */
    public refractionY(rad: number) {
        return Math.atan2(Math.sin(rad), -Math.cos(rad));
    };
    /** 弧度折射X轴 */
    public refractionX(rad: number) {
        return Math.atan2(-Math.sin(rad), Math.cos(rad));
    };
    /** 重新洗牌 一个数组 */
    public aginSortArr(Arr: Array<any>) {
        for (let i = 0; i < Arr.length; i++) {
            let tempR = Tools.random(0, Arr.length - 1);
            if (tempR != i) {
                let temp = Arr[i];
                Arr[i] = Arr[tempR];
                Arr[tempR] = temp;
            }
        }
    }
    /** 数组 对象排序  对象属性  是否倒序 */
    public sortArrForObject(tempArr: Array<any>, sortName: string, isReverse = false) {
        if (!isReverse) {
            tempArr.sort((a, b) => {
                return a[sortName] - b[sortName];
            });
        } else {
            tempArr.sort((a, b) => {
                return b[sortName] - a[sortName];
            });
        }
    };
    /** 取一定范围内不重复的数字 */
    public getDiffNumRandom(minNum: number, maxNum: number, getNum: number) {
        var arr = [];
        for (let i = minNum; i <= maxNum; i++) {
            arr.push(i);
        }
        const tempLen = arr.length - getNum;
        for (let i = 0; i < tempLen; i++) {
            let tempI = Tools.random(0, arr.length - 1);
            arr.splice(tempI, 1);
        }
        return arr;
    };
    /**数字转中文 */
    public DigitToChinese(digit: number): string {
        let chnNum = ["零", "一", "二", "三", "四", "五", "六", "七", "八", "九"];
        let chnNumUnit = ["", "十", "百", "千"];
        let tmp = "";
        let chnString = "";
        let zero = true;
        let unitIndex = 0;
        let isTen = false;
        if (digit > 9 && digit < 20) {
            isTen = true;
        }
        while (digit > 0) {
            let num = digit % 10;
            if (num === 0) {
                if (!zero) {
                    zero = true;
                    chnString = chnNum[num] + chnString;
                }
            }
            else {
                zero = false;
                if (isTen && unitIndex == 1) {
                    tmp = "";
                }
                else {
                    tmp = chnNum[num];
                }
                tmp += chnNumUnit[unitIndex];
                chnString = tmp + chnString;
            }
            unitIndex++;
            digit = Math.floor(digit / 10);
        }
        return chnString;
    }
}
/** 向量坐标转换相关工具类 */
class VectTools {
    /** 单例模式 */
    private static _instance: VectTools = new VectTools();
    private constructor() { }
    public static get _ins() {
        return this._instance;
    }

    /** 根据两个点  求角度 */
    public getAngleForPos(pos1: cc.Vec2, pos2: cc.Vec2, isVertical = false): number {
        let rad = 0;
        if (isVertical) {
            rad = -Math.atan2(pos2.x - pos1.x, pos2.y - pos1.y);
        } else {
            rad = Math.atan2(pos2.y - pos1.y, pos2.x - pos1.x);
        }
        return cc.misc.radiansToDegrees(rad);
    }
    /** 获取两个坐标之间的距离 */
    public getDistance(pos1: cc.Vec2, pos2: cc.Vec2): number {
        return pos1.sub(pos2).mag();
    };
    /** 根据一个角度和长度 计算相对应的坐标 */
    public getPosForAngleLen(angle: number, len: number, startPos: cc.Vec2 = cc.v2(0, 0)) {
        let rad = cc.misc.degreesToRadians(angle);
        return cc.v3(startPos.x + Math.cos(rad) * len, startPos.y + Math.sin(rad) * len);
    }
    /** 获取节点在另一个节点下的坐标 */
    public getToNodePosForNode(obj: cc.Node, mainObj: cc.Node): cc.Vec2 {
        let worldPos = obj.parent.convertToWorldSpaceAR(obj.position);
        let nodePos = mainObj.convertToNodeSpaceAR(worldPos)
        return cc.v2(nodePos.x, nodePos.y);
    };
    /** 获取节点的世界坐标 */
    public getToWorldPosAR(obj: cc.Node) {
        return obj.parent.convertToWorldSpaceAR(obj.position);
    }
    /** 通过世界坐标 获取相对节点的坐标 */
    public getToNodePosForWorld(worldPos: cc.Vec2, obj: cc.Node) {
        return obj.convertToNodeSpaceAR(worldPos);
    }
}
